import { InjectableObject } from "../../inject";
import { ECSComponent } from "../component/ECSComponent";
import { Constructor, ECSWorld } from "../ECSWorld";

/**
 * 用于生成实体唯一 ID
 */
let nextEntityId: number = 0;

export class ECSEntity extends InjectableObject {
    readonly id: string;

    readonly components = new Map<string, ECSComponent>();

    private enabled = false;

    private ecsWorld: ECSWorld | undefined;

    get ecs(): ECSWorld {
        if (!this.ecsWorld) {
            throw new TypeError("[ECS] System.ecs is undefined");
        }
        return this.ecsWorld;
    }

    set ecs(ecs: ECSWorld | undefined) {
        this.ecsWorld = ecs;
    }

    constructor() {
        super();

        nextEntityId++;
        this.id = nextEntityId.toString();
    }

    isEnabled(): boolean {
        return this.enabled;
    }

    setEnabled(enabled: boolean): ECSEntity {
        if (this.enabled === enabled || !this.ecs.components) {
            return this;
        }

        this.enabled = enabled;

        const compsRef = this.ecs.components;
        if (enabled) {
            // 把组件添加到全局组件列表
            this.components.forEach((component) => compsRef.add(component));
        } else {
            // 从全局组件列表移除组件
            this.components.forEach((component) => compsRef.delete(component));
        }

        return this;
    }

    /**
     * 添加组件到实体
     *
     * @param component
     */
    addComponent(component: ECSComponent): ECSEntity {
        const name = component.name;
        if (this.components.has(name)) {
            throw new Error(
                `[ECS] component '${name}' already exists in entity '${this.id}'`
            );
        }
        component.entityId = this.id;

        if (this.ecs.components) {
            this.ecs.components.add(component);
        }

        this.components.set(name, component);

        return this;
    }

    /**
     * 检查指定的组件是否存在
     *
     * @param constructor
     */
    hasComponent<T extends ECSComponent>(
        constructor: Constructor<T>
    ): boolean {
        return this.components.has(constructor.name);
    }

    /**
     * 取得指定名字的组件
     *
     * @param constructor
     */
    getComponent<T extends ECSComponent>(constructor: Constructor<T>): T {
        const name = constructor.name;
        const component = this.components.get(name);
        if (!component) {
            throw new Error(
                `[ECS] not found component '${name}' in entity '${this.id}'`
            );
        }
        return component as T;
    }

    /**
     * 移除组件
     *
     * @param constructor
     */
    removeComponent<T extends ECSComponent>(constructor: Constructor<T>): ECSEntity {
        const name = constructor.name;
        const component = this.components.get(name);
        if (!component) {
            throw new Error(
                `[ECS] not found component '${name}' in entity '${this.id}'`
            );
        }
        if (this.ecs.components) {
            this.ecs.components.delete(component);
        }
        this.components.delete(name);
        return this;
    }

    /**
     * 移除所有组件
     */
    removeAllComponents(): ECSEntity {
        if (this.ecs.components) {
            const ref = this.ecs.components;
            this.components.forEach((component) => ref.delete(component));
        }
        this.components.clear();
        return this;
    }
}